`include "instruction_def.v"
`include "ctrl_encode_def.v"
module Ctrl(
	clk, 
	RegDst,Branch,MemR,Mem2R,MemW,RegW,
	Alusrc,Alusrc1,ExtOp,Aluctrl,NPCOp,
	OpCode,funct, 
	RD1, RD2, beq_zero, 
	EX_MemR, EX_rt, EX_rs, rt, rs, 
	PCWr, IFID_Wr
	);

	input clk;

	input EX_MemR; 
    input [4:0] EX_rt;
    input [4:0] EX_rs; 
    input [4:0] rt;
    input [4:0] rs;
    output reg PCWr;
    output reg IFID_Wr;



	input [5:0]		OpCode;				//指令操作码字段
	input [5:0]		funct;				//指令功能字段
	input [31:0] RD1;
	input [31:0] RD2;

	output reg[1:0] RegDst;						
	output reg Branch;						//分支
	output reg MemR;						//读存储器
	output reg[1:0] Mem2R;						//数据存储器到寄存器堆
	output reg MemW;						//写数据存储器
	output reg RegW;						//寄存器堆写入数据
	output reg Alusrc;						//运算器操作数选择
	output reg Alusrc1;
	output reg[1:0] NPCOp;
	output reg[1:0] ExtOp;						//位扩展/符号扩展选择
	output reg[4:0] Aluctrl;
	output reg beq_zero;

	always @(EX_MemR, EX_rt, EX_rs, rt, rt) begin
    if (EX_MemR && ((EX_rt == rs) || (EX_rt == rt)))
    begin
        PCWr = 0;
        IFID_Wr = 0;
        MemW = 0;
        RegW = 0;
    end
    else
    begin
        PCWr = 1;
        IFID_Wr = 1;
    end
 	end

	always @(OpCode or funct, posedge clk)
	begin
	case (OpCode)
		`INSTR_RTYPE_OP:
		begin
			RegDst  = 1;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 0;
			Alusrc1 = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_ZERO;
			NPCOp   = `NPC_PLUS4;
			case (funct)
				`INSTR_ADD_FUNCT:
					Aluctrl = `ALUOp_ADD;
				`INSTR_ADDU_FUNCT:
					Aluctrl = `ALUOp_ADDU;
				`INSTR_SUB_FUNCT:
					Aluctrl = `ALUOp_SUB;
				`INSTR_SUBU_FUNCT:
					Aluctrl = `ALUOp_SUBU;
				`INSTR_AND_FUNCT:
					Aluctrl = `ALUOp_AND;
				`INSTR_OR_FUNCT:
					Aluctrl = `ALUOp_OR;
				`INSTR_SLT_FUNCT:
					Aluctrl = `ALUOp_SLT;
				`INSTR_SLL_FUNCT:
				begin
					Aluctrl = `ALUOp_SLL;
					Alusrc  = 1;
					Alusrc1  = 1;
				end
				`INSTR_SRL_FUNCT:
				begin
					Aluctrl = `ALUOp_SRL;
					Alusrc  = 1;
					Alusrc1  = 1;
				end
				`INSTR_SRA_FUNCT:
				begin
					Aluctrl = `ALUOp_SRA;
					Alusrc  = 1;
					Alusrc1  = 1;
				end
				`INSTR_JR_FUNCT:
				begin
					Aluctrl = `ALUOp_ADD;
					NPCOp   = `NPC_JR;
					
				end
			endcase
		end
 
		`INSTR_LW_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 1;
			Mem2R   = 1;
			MemW    = 0;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_ADD;
			NPCOp   = `NPC_PLUS4;
		end

		`INSTR_SW_OP:
		begin
			Branch  = 0;
			MemR    = 0;
			MemW    = 1;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 0;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_ADD;
			NPCOp   = `NPC_PLUS4;
		end

		`INSTR_ADDI_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_ADD;
			NPCOp   = `NPC_PLUS4;
		end

		`INSTR_ORI_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_ZERO;
			Aluctrl = `ALUOp_OR;
			NPCOp   = `NPC_PLUS4;
		end

		`INSTR_LUI_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_HIGHPOS;
			Aluctrl = `ALUOp_OR;
			NPCOp   = `NPC_PLUS4;
		end

		`INSTR_SLTI_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 1;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_SLT;
			NPCOp   = `NPC_PLUS4;
		end



		`INSTR_BEQ_OP:
		begin
			Branch  = 1;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 0;
			Alusrc1 = 0;
			RegW    = 0;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_EQL;
			NPCOp   = `NPC_BRANCH;
			
				
		end

		`INSTR_BNE_OP:
		begin
			Branch  = 1;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 0;
			Alusrc1 = 0;
			RegW    = 0;
			beq_zero = 0;
			
			ExtOp   = `EXT_SIGNED;
			Aluctrl = `ALUOp_BNE;
			NPCOp   = `NPC_BRANCH;
				
		end


		`INSTR_J_OP:
		begin
			RegDst  = 0;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 0;
			MemW    = 0;
			Alusrc  = 0;
			Alusrc1 = 0;
			RegW    = 0;
			beq_zero = 0;
			
			ExtOp   = `EXT_ZERO;
			Aluctrl = `ALUOp_ADD;
			NPCOp   = `NPC_JUMP;
		end


		`INSTR_JAL_OP:
		begin
			RegDst  = 2;
			Branch  = 0;
			MemR    = 0;
			Mem2R   = 2;
			MemW    = 0;
			Alusrc  = 0;
			Alusrc1  = 0;
			RegW    = 1;
			beq_zero = 0;
			
			ExtOp   = `EXT_ZERO;
			Aluctrl = `ALUOp_ADD;
			NPCOp   = `NPC_JUMP;
		end


	endcase
	end


endmodule
